package com.opdar.platform.core.base;

import com.opdar.platform.annotations.*;
import com.opdar.platform.core.convert.DefaultJSONConvert;
import com.opdar.platform.core.convert.JSONConvert;
import com.opdar.platform.gateway.point.PointManager;
import com.opdar.platform.utils.Utils;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by shiju on 2017/1/18.
 */
public class ServletEventListener implements ServletContextListener {
    private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        for (String beanName : applicationContext.getBeanDefinitionNames()) {
            Controller controller = applicationContext.findAnnotationOnBean(beanName, Controller.class);
            if (controller != null) {
                Class<?> clz = applicationContext.getType(beanName);
                createRouter(clz,applicationContext);
            }
        }
        RouterManager.sort();
        servletContextEvent.getServletContext().setAttribute(Context.APPLICATION_CONTEXT, applicationContext);
    }

    private void createRouter(Class<?> clz, ApplicationContext applicationContext) {
        List<Interceptor> interceptorByType = new LinkedList<Interceptor>();
        List<ErrorHandler> errorHandlers = new LinkedList<ErrorHandler>();
        List<Editor> editorList = new LinkedList<Editor>();
        JSONConvert jsonConvert = null;
        {
            //查询Class上的拦截器
            com.opdar.platform.annotations.Interceptor interceptor = AnnotationUtils.findAnnotation(clz, com.opdar.platform.annotations.Interceptor.class);
            com.opdar.platform.annotations.ErrorHandler errorHandler = AnnotationUtils.findAnnotation(clz, com.opdar.platform.annotations.ErrorHandler.class);
            com.opdar.platform.annotations.Editor editor = AnnotationUtils.findAnnotation(clz, com.opdar.platform.annotations.Editor.class);
            addInterceptors(interceptorByType, interceptor, applicationContext);
            addErrorHandler(errorHandlers, errorHandler,applicationContext);
            addEditor(editorList,editor,applicationContext);
        }
        try{
            jsonConvert = applicationContext.getBean(JSONConvert.class);
        }catch (Exception e){
        }
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clz);
        for (Method method : methods) {
            method.setAccessible(true);
            Request request = AnnotationUtils.findAnnotation(method, Request.class);
            if (request != null) {
                String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
                String routerName = request.value();
                if (StringUtils.isEmpty(routerName)) {
                    routerName = method.getName();
                }
                int version = request.version();
                Request.Format format = request.format();
                Request.Method method1 = request.method();
                SecretType secretType = request.secret();
                String secretKey = request.secretKey();
                boolean hasToken = request.hasToken();
                boolean restful = request.restful();

                Router router = null;
                if(restful){
                    router = new RestRouter(Utils.testRouter(routerName));
                }else{
                    router = new Router(Utils.testRouter(routerName));
                }
                router.setVersion(version);
                router.setFormat(format);
                router.setMethod(method1);
                router.setHasToken(hasToken);
                router.setSecretType(secretType);
                router.setSecretKey(secretKey);
                router.setHandler(new MethodInvokeHandler(method, parameterNames).setJsonConvert(jsonConvert));
                RouterManager.add(router);

                {
                    {
                        //查询方法上的拦截器
                        com.opdar.platform.annotations.Interceptor interceptor = AnnotationUtils.findAnnotation(method, com.opdar.platform.annotations.Interceptor.class);
                        //合并Class上的拦截器
                        List<Interceptor> interceptorByMethod = new LinkedList<Interceptor>();
                        interceptorByMethod.addAll(interceptorByType);
                        addInterceptors(interceptorByMethod, interceptor,applicationContext);
                        router.getHandler().setInterceptors(interceptorByMethod);

                    }
                    {
                        com.opdar.platform.annotations.ErrorHandler errorHandler = AnnotationUtils.findAnnotation(method, com.opdar.platform.annotations.ErrorHandler.class);
                        List<ErrorHandler> errorHandlerByMethod = new LinkedList<ErrorHandler>();
                        errorHandlerByMethod.addAll(errorHandlers);
                        addErrorHandler(errorHandlerByMethod, errorHandler,applicationContext);
                        router.getHandler().setErrorHandlers(errorHandlerByMethod);
                    }
                    {
                        com.opdar.platform.annotations.Editor editor = AnnotationUtils.findAnnotation(method, com.opdar.platform.annotations.Editor.class);
                        List<Editor> editorByMethod = new LinkedList<Editor>();
                        editorByMethod.addAll(editorList);
                        addEditor(editorByMethod,editor,applicationContext);
                        router.getHandler().setEditorList(editorByMethod);
                    }
                }
            }
        }
    }

    private void addEditor(List<Editor> editorList, com.opdar.platform.annotations.Editor editor, ApplicationContext applicationContext) {
        if (editor != null) {
            for (Class<? extends Editor> editorClz : editor.value()) {
                Editor editorInstance = (Editor) ReflectUtils.newInstance(editorClz);
                if(ApplicationContextAware.class.isAssignableFrom(editorClz)){
                    ApplicationContextAware applicationContextAware = (ApplicationContextAware) editorInstance;
                    applicationContextAware.setApplicationContext(applicationContext);
                }
                editorList.add(editorInstance);
            }
        }
    }

    private void addErrorHandler(List<ErrorHandler> errorHandlers, com.opdar.platform.annotations.ErrorHandler errorHandler, ApplicationContext applicationContext) {
        if(errorHandler != null){
            Class<? extends ErrorHandler> errHandler = errorHandler.value();
            ErrorHandler errorHandler1 = (ErrorHandler) ReflectUtils.newInstance(errHandler);
            if(ApplicationContextAware.class.isAssignableFrom(errHandler)){
                ApplicationContextAware applicationContextAware = (ApplicationContextAware) errorHandler1;
                applicationContextAware.setApplicationContext(applicationContext);
            }
            errorHandlers.add(errorHandler1);
        }
    }

    private void addInterceptors(List<Interceptor> interceptorByType, com.opdar.platform.annotations.Interceptor interceptor, ApplicationContext applicationContext) {
        if (interceptor != null) {
            for (Class<? extends Interceptor> interceptorClz : interceptor.value()) {
                Interceptor interceptor1 = (Interceptor) ReflectUtils.newInstance(interceptorClz);
                if(ApplicationContextAware.class.isAssignableFrom(interceptorClz)){
                    ApplicationContextAware applicationContextAware = (ApplicationContextAware) interceptor1;
                    applicationContextAware.setApplicationContext(applicationContext);
                }
                interceptorByType.add(interceptor1);
            }
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        ClassPathXmlApplicationContext applicationContext = (ClassPathXmlApplicationContext) servletContextEvent.getServletContext().getAttribute(Context.APPLICATION_CONTEXT);
        applicationContext.stop();
    }
}
